﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vowei.Core.Models;
using System.Diagnostics;
using Vowei.Core;

namespace Vowei.Data.Helpers
{
    public static class ImportHelper
    {
        public static void ImportDataTo(Project project, IVoweiContext context, IEnumerable<ITable> items, IUser user)
        {
            var milestones = items.OfType<Milestone>();
            foreach (var milestone in milestones)
            {
                if (milestone.BelongsToMilestone == null)
                {
                    milestone.BelongsToMilestone = project;
                    project.Children.Add(milestone);
                }
            }

            foreach (var item in items.OfType<Ticket>())
            {
                //if (!context.Tickets.Query.Any(t => t.ID == item.ID) && item.BelongsToMilestone == null)
                //    item.BelongsToMilestone = project;
                if (!context.Tickets.Query.Any(t => t.ID == item.ID))
                {
                    if ( item.BelongsToMilestone == null && item.BelongsToMilestoneId == null )
                        item.BelongsToMilestone = project;
                }
                else
                    item.BelongsToMilestone = context.Milestones.Find(item.BelongsToMilestoneId);
            }

            foreach (var item in items)
            {
                if (item is Milestone)
                    EditingHelpers.GenericEndEdit<Milestone>((Milestone)item, context, user);
                else if (item is Ticket)
                    EditingHelpers.GenericEndEdit<Ticket>((Ticket)item, context, user);
                else
                    Trace.TraceWarning(string.Format("不支持导入类型为[{0}]的数据！", item.GetType()));
            }

            // 修复项目的起始日期和结束日期
            DateTime minStartDate = DateTime.MaxValue, maxDueDate = DateTime.MinValue;

            if (milestones.Count() > 0)
            {
                minStartDate = milestones.Min(m => m.StartDate.HasValue ? m.StartDate.Value : DateTime.MaxValue);
                maxDueDate = milestones.Max(m => m.DueDate.HasValue ? m.DueDate.Value : DateTime.MinValue);
            }

            var tasks = items.OfType<Task>();
            if (tasks.Count() > 0)
            {
                minStartDate = tasks.Min(t => t.StartDate.HasValue ? t.StartDate.Value : minStartDate);
                maxDueDate = tasks.Max(t => t.DueDate.HasValue ? t.DueDate.Value : maxDueDate);
            }

            project.StartDate = project.StartDate.HasValue ? (project.StartDate.Value > minStartDate ? minStartDate : project.StartDate.Value)
                : (minStartDate == DateTime.MaxValue ? project.StartDate : minStartDate);
            project.DueDate = project.DueDate.HasValue ? (project.DueDate.Value < maxDueDate ? maxDueDate : project.DueDate.Value)
                : (maxDueDate == DateTime.MinValue ? project.DueDate : maxDueDate);

            try
            {
                context.SaveChanges();
            }
            catch (System.Data.Entity.Validation.DbEntityValidationException e)
            {
                foreach (var error in e.EntityValidationErrors)
                {
                    Trace.WriteLine(string.Format("[IVoweiContext.ImportProjectData]: {0}, Error details: \n _____________________",
                        ((INamedTable)error.Entry.Entity).Title));

                    foreach (var de in error.ValidationErrors)
                        Trace.WriteLine(string.Format("属性: {0} -> {1}", de.PropertyName, de.ErrorMessage));
                }

                throw e;
            }
        }

        public static void ImportDataTo(Requirement requirement, IVoweiContext context, IEnumerable<ITable> items, IUser user)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            if (user == null)
                throw new ArgumentNullException("user");
            if (items == null || items.Count() == 0)
                return;

            // 只支持增量加载
            var detailed = context.Requirements.Include("Children").Query.First(r => r.ID == requirement.ID);
            var tickets = detailed.AllTickets(context);
            foreach (Ticket item in items)
            {
                if (item == null) continue;

                if (!tickets.Any(t => t.ID == item.ID))
                {
                    // 新创建的任务，放在跟当前需求同一天完成
                    if (!item.BelongsToMilestoneId.HasValue)
                        item.BelongsToMilestoneId = detailed.BelongsToMilestoneId;

                    detailed.Children.Add(item);
                }

                EditingHelpers.GenericEndEdit<Ticket>(item, context, user, new string[] { 
                        "BelongsToMilestone", "BelongsToMilestoneId", "ParentId" });
            }

            context.SaveChanges();
        }
        
        public static void AssignMemberTo(Project project, IVoweiContext context, Employee user, ITranslator translator)
        {
            if (project == null) throw new ArgumentNullException("project");
            if (context == null) throw new ArgumentNullException("context");
            if (user == null) throw new ArgumentNullException("user");

            AddNewEmployee(context, user);

            if (!AddNewAssignment(project, context, new ResourceAssignment
                {
                    ProjectId = project.ID,
                    ResourceId = user.ID
                }))
            {
                Trace.TraceWarning(string.Format(translator.T("用户{0}已经存在于项目组{1}中了!"), user.Email, project.Title));
            }
        }

        public static void ImportAssignmentTo(
            Project project, IVoweiContext context, IEnumerable<ResourceAssignment> assignments, IEnumerable<Employee> members, ITranslator translator)
        {
            if (project == null) throw new ArgumentNullException("project");
            if (context == null) throw new ArgumentNullException("context");
            if (members == null) throw new ArgumentNullException("members");
            if (assignments == null) throw new ArgumentNullException("assignments");

            Debug.Assert(assignments.Count() == members.Count());
            var aiter = assignments.GetEnumerator();
            var miter = members.GetEnumerator();
            var pid = project.ID;
            project = context.Projects.Include("ProjectBaseCalendar").Query.Single(p => p.ID == pid);

            aiter.Reset();
            miter.Reset();

            while (aiter.MoveNext() && miter.MoveNext())
            {
                var dbEmployee = AddNewEmployee(context, miter.Current);
                var assignment = aiter.Current;
                assignment.ResourceId = dbEmployee.ID;
                assignment.ProjectId = pid;

                if (!AddNewAssignment(project, context, assignment))
                {
                    var dbas = project.ResourceAssignments.Single(t => t.ResourceId == assignment.ResourceId && t.ProjectId == assignment.ProjectId);
                    dbas.CostPerHour = assignment.CostPerHour;
                }
            }

            context.SaveChanges();
        }

        private static Employee AddNewEmployee(IVoweiContext context, Employee user)
        {
            if (context == null) throw new ArgumentNullException("context");
            if (user == null) throw new ArgumentNullException("user");

            // TODO: 下面使用Email进行匹配的方式，很有可能会没有办法支持使用windows身份验证的用户
            var employee = context.Employees.Find(user.Email);
            if (employee == null)
            {
                context.Employees.Add(user);
                return user;
            }
            else
            {
                return employee;
            }
        }

        private static bool AddNewAssignment(Project project, IVoweiContext context, ResourceAssignment assignment)
        {
            if (context == null) throw new ArgumentNullException("context");
            if (assignment == null) throw new ArgumentNullException("assignment");
            
            var rid = assignment.ResourceId;
            var pid = assignment.ProjectId;
            if (!project.ResourceAssignments.Any(t => t.ResourceId == rid && t.ProjectId == assignment.ProjectId))
            {
                assignment.WorkCalendar = project.ProjectBaseCalendar;
                project.ResourceAssignments.Add(assignment);
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
